/***************************************************
> Copyright (C) 2024 ==QWZL== All rights reserved.
> File Name: WPH_server.c
> Author:nxq
> Mail:nxq949698473@163.com 
> Created Time: 2024年07月23日 星期二 20时00分16秒
***************************************************/

#include "WPH_server.h"
#include "sql.h"
#include "register.h"
#include "log_staff.h"
#include "account.h"
#include "deleteInfo.h"
#include "state.h"
#include "collectInfo.h"
#include "sys_log.h"

//epoll
void epoll_server()
{
    struct epoll_event ev;
    memset(&ev,0,sizeof(ev));
    struct epoll_event events[100];
    memset(events,0,sizeof(events));

    int listen_sock = 0;//监听套接字
    int conn_sock = 0;//通信套接字
    int nfds = 0;//活跃套接字个数
    int epollfd = 0;//epoll文件描述符
    int n = 0;
    int ret = 0;
    
    struct sockaddr_in addr;
    memset(&addr,0,sizeof(addr));

    MYSQL *mysql = NULL;
    MYSQL *res = NULL;
    char sql[1024] = {0};
    
    mysql = mysql_init(NULL);//初始化
    res = mysql_real_connect(mysql,"localhost","","","water",0,NULL,0);
    if(res == NULL)
    {
        LOG_E("%s",mysql_error(mysql));
        mysql_close(mysql);
         return ;
    }

    //管理员
    struct regulator info;
    memset(&info,0,sizeof(info));
    //员工
    struct staff staff_info;
    memset(&staff_info,0,sizeof(staff_info));

    listen_sock = linstenSock();//监听套接字

    epollfd = epoll_create1(0);//创建一个epoll句柄
    if(epollfd == -1)
    {
        LOG_E("epoll_create1\n");
        exit(EXIT_FAILURE);
    }

    ev.events = EPOLLIN;//表示相应的文件描述符能够读
    ev.data.fd = listen_sock;//设置与要处理事件相关的文件描述符

    //epoll的事件注册函数，注册新的监听套接字描述符到epollfd中
    ret = epoll_ctl(epollfd,EPOLL_CTL_ADD,listen_sock,&ev);
    if(ret == -1)
    {
        LOG_E("epoll_ctl:listen_sock\n");
        exit(EXIT_FAILURE);
    }

    for(;;)
    {
        //等待事件的产生，返回需要处理的事件的数量，并将需处理时间的套接字集合于events中，遍历events处理事件
        //nfds:活跃连接个数
        nfds = epoll_wait(epollfd,events,100,-1);
        LOG_D("nfds = %d\n",nfds);
        if(nfds == -1)
        {
            LOG_E("epoll_wait\n");
            exit(EXIT_FAILURE);
        }
        if(nfds == 0)
        {
            LOG_E("epoll_wait() timeout.\n");
            continue;
        }
    
        for(n = 0;n < nfds; n++)//依次处理活跃套接字,有事件发生
        {
            //if(events[n].data.fd == listen_sock)//有新的连接
            if((events[n].data.fd == listen_sock) && (events[n].events & EPOLLIN))
            {
                int len = sizeof(addr);
                //conn_sock = accept(listen_sock,NULL,NULL);
                conn_sock = accept(listen_sock,(struct sockaddr*)&addr,&len);

                LOG_D("conn_sock：%d\n",conn_sock);
                if(conn_sock == -1)
                {
                    LOG_E("accept\n");
                    exit(EXIT_FAILURE);
                }
                printf("acceptd connection from %s, port %d\n",inet_ntoa(addr.sin_addr),htons(addr.sin_port));
                
                setnonblocking(conn_sock);//转为非阻塞

                //加到套接字集中
                memset(&ev,0,sizeof(struct epoll_event));
                ev.events = EPOLLIN | EPOLLET;//对读感兴趣，边沿触发
                ev.data.fd = conn_sock;

                ret = epoll_ctl(epollfd,EPOLL_CTL_ADD,conn_sock,&ev);//注册新的fd到epollfd中
                if(ret == -1)//新增套接字
                {
                    LOG_E("epoll_cti:conn_sock\n");
                    exit(EXIT_FAILURE);
                }
                
                sprintf(sql,"connection: %s, port: %d",inet_ntoa(addr.sin_addr),htons(addr.sin_port));
                log_event(mysql, sql);

                continue;
            }
            else//通信套接字，处理数据（判断是通信套接字活跃还是监听套接字活跃）
            {
                char buf[1024] = {0};          

                //接收数据   
                ret = recv(events[n].data.fd,buf,sizeof(buf),0);
                LOG_D("ret = %d\n",ret);
                if(ret <= 0)//客户端下线
				{
					ev.data.fd = events[n].data.fd;
					ev.events = EPOLLIN | EPOLLET;
					ret = epoll_ctl(epollfd,EPOLL_CTL_DEL,events[n].data.fd,&ev);//从epollfd中删除一个fd
                    LOG_D("ret = %d\n",ret);
					if(ret == -1)
					{
                        LOG_E("epoll_ctl:delete\n");
						exit(EXIT_FAILURE);
					}
					close(ev.data.fd);
                    continue;
				}
                LOG_D("%s\n",buf);

                char type[30] = {0};
                strcpy(type,funType(buf,type));//解包type键

                LOG_D("type = %s\n",type);
                printf("type = %s\n",type);
                if(strcmp(type,"Administratorregistration") == 0)
                {
                    strcpy(sql,"管理员注册");
                    log_event(mysql, sql);
                    managerReguster(events[n].data.fd,buf); //管理员注册
                    continue;
                }
                if(strcmp(type ,"Employeeregistration") == 0)
                {
                    strcpy(sql,"员工注册");
                    log_event(mysql, sql);
                    staffReguster(events[n].data.fd,buf); //员工注册
                    continue;
                }
                if(strcmp(type ,"Administratorlogin") == 0)
                {
                    strcpy(sql,"管理员登录");
                    log_event(mysql, sql);
                    managerLog(events[n].data.fd,buf);//管理员登录
                    continue;
                }    
                if(strcmp(type ,"Employeelogin") == 0)
                {
                    strcpy(sql,"员工登录");
                    log_event(mysql, sql);
                    staffLog(events[n].data.fd,buf);//员工登录 
                    continue;
                }  
                if(strcmp(type,"view") == 0)
                {
                    strcpy(sql,"查询水泵信息");
                    log_event(mysql, sql);
                    viewInfo(buf,events[n].data.fd);//查询
                    continue;
                } 
                if(strcmp(type,"delete") == 0)
                {
                    strcpy(sql,"删除水泵信息");
                    log_event(mysql, sql);
                   delInfo(buf,events[n].data.fd);//删除
                   continue;
                }
                if(strcmp(type,"Switch") == 0)
                {
                   wphState(events[n].data.fd,buf);//开关状态
                   continue;
                }
                if((strcmp(type,"wph1") == 0)|| (strcmp(type,"wph2") == 0)|| (strcmp(type,"wph3") == 0))  
                {
                    strcpy(sql,"采集水泵信息");
                    log_event(mysql, sql);
                    gatherInfo(events[n].data.fd,buf);//采集信息
                    continue;
                } 
                if(strcmp(type,"Logs") == 0)//查询日志
                {
                    strcpy(sql,"查询日志");
                    log_event(mysql, sql);
                    logQuery(buf,events[n].data.fd);
                }  
            }
        }
    }
    close(listen_sock);
}

//获取监听套接字
int linstenSock()
{
    int ret = 0;
    int listen_sock = 0;
	struct sockaddr_in addr;
	memset(&addr,0,sizeof(addr));

	listen_sock = socket(AF_INET,SOCK_STREAM,0);
	if(listen_sock == -1)
	{
        LOG_E("socket\n");
		exit(-1);
	}

	addr.sin_family = AF_INET;
	addr.sin_port = htons(6666);
	addr.sin_addr.s_addr = inet_addr("192.168.0.185");

	ret = bind(listen_sock,(struct sockaddr *)&addr,sizeof(struct sockaddr));
	if(ret == -1)
	{
        LOG_E("bind\n");
		exit(-1);
	}

	ret = listen(listen_sock,5);
	if(ret == -1)
	{
        LOG_E("listen\n");
        exit(-1);
	}

    return listen_sock;
}

//转为非阻塞
void setnonblocking(int sockfd) 
{  
    int opts;  
    
    opts = fcntl(sockfd, F_GETFL);  
    if(opts < 0) 
    {   
        LOG_E("fcntl(F_GETFL\n");
        exit(-1);  
    }  
    opts = (opts | O_NONBLOCK);  
    if(fcntl(sockfd, F_SETFL, opts) < 0) 
    {   
        LOG_E("fcntl(F_SETFL)\n"); 
        exit(-1);  
    }  
}

// 记录事件到日志
void log_event(MYSQL *mysql, const char *event) 
{
    char sql[1024] = {0};
    int ret = 0;

    sprintf(sql, "insert into logTable (event, time) values ('%s', now())", event);
    ret = mysql_query(mysql,sql);
	if(ret != 0)
	{
		LOG_E("%s\n",mysql_error(mysql));
		mysql_close(mysql);
		exit(-1);
	}

    mysql_free_result(mysql_store_result(mysql));
}
